﻿using System;
using System.Collections.Generic;
using System.Xml;
using AventStack.ExtentReports.Utils;
using Ro.AssistFunction.OutputManage;
using Ro.AssistFunction.SerializerChildNodes;
using Ro.Common.RoArgs;
using Ro.Common.RoInterface;
using Ro.Common.RoInterface.UserType;
using Ro.Interpreter.InterAssistFunc;
using Ro.Interpreter.RunLogic;

namespace Ro.Interpreter.Cores
{
    /* 解释器基础核心功能
     * 通过解析内部结构转为.net type, 通过逻辑层进行处理
     * TODO 3-14 重新修改，之前写的太乱了,至3-23日继续更改
     * TODO 3-29 又双叒改了，原反序列化的方法会导致很多很多很多问题，而且也很难理解反序列化的时候还必须将 .Net Type中包含的 .Net Type初始化一次
     * TODO 4-25 重大更新，需要预留给Config文件的接口，在TestConfigNodes中进行处理Config
     * 这个文件非常重要！！！
     */

    /// <summary>
    /// 接口实现
    /// 将脚本一级子节点转换为对应的类、方法
    /// 在方法RoTcsFileMainEvent.TcsEventMain中被调用
    /// </summary>
    public class InterFuncCores : IInterFuncCores
    {
        /// <summary>
        /// 反序列化子节点的方法，从下放各个方法提取出，进行共用
        /// </summary>
        readonly NewSerChildNode _newSerChildNode = new NewSerChildNode();

        /// <summary>
        /// Annotation节点处理
        /// 对应信息写入extentreport
        /// </summary>
        /// <param name="xmlNode">Annotation节点</param>
        /// <returns>返回是否正常完成</returns>
        public bool AnnotationNodes(XmlNode xmlNode)
        {
            try
            {
                //3-29通过新方法回调,反馈Annotation回调信息
                Annotation annotation = _newSerChildNode.SerAnnotationNode(xmlNode);

                if (annotation == null)
                {
                    //添加输出
                    if (RoPubArgments.ProTips)
                    {
                        RoOutputToGui roOutputToGui = new RoOutputToGui();
                        //获取当前时间
                        string nowtime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
                        roOutputToGui.OutDetail(nowtime, "方法AnnotationNodes执行失败，反序列化获取Annotation信息失败，获取值为NULL");
                    }
                    else
                    {
                        RoPubArgments.RoOutputToConsole.OutputConsole(RoLogStatus.Fatal, "方法AnnotationNodes执行失败，反序列化获取Annotation信息失败，获取值为NULL");
                    }

                    RoPubArgments.RoLog.Fatal("方法AnnotationNodes执行失败，反序列化获取Annotation信息失败，获取值为NULL");
                    return false;
                }

                //写入信息到extentreport中
                RoPubArgments.RoExtentReports.AddSystemInfo("Description", annotation.Description);
                RoPubArgments.RoExtentReports.AddSystemInfo("CreateAuthor", annotation.Created.Author);
                RoPubArgments.RoExtentReports.AddSystemInfo("CreateDate", annotation.Created.Date);

                //返回
                return true;
            }
            catch (Exception e)
            {
                //添加输出
                ExceptionOutPut.SystemExceptionOut("AnnotationNodes", e);
                return false;
            }
        }

        /// <summary>
        /// TestConfig节点处理
        /// <para>节点完成后会自动生成多个全局变量存放变量和tci文件中的元素</para>
        /// </summary>
        /// <param name="xmlNode">TestConfig节点</param>
        /// <returns>返回是否正常完成</returns>
        public bool TestConfigNodes(XmlNode xmlNode)
        {
            try
            {
                //本方法正确或错误
                bool argsResult;
                bool tciResult;

                //todo (1)现有的参数分为2类，一类通过命令行设置，一类通过TCS文件相关节点设置 因此要合并一个list内，直接将通过tcs设置的参数更新到命令行传入的参数中

                List<Property> propertylist = _newSerChildNode.SerPropertyNode(xmlNode.FirstChild);

                //验证是否为空
                if (propertylist != null)
                {
                    //todo 2017-05-03 更新Pro版本的参数传入
                    if (RoPubArgments.ProTips)
                    {
                        //Pro版本，不存在命令行传入值，因此SystemProperties是个空值，需要将tcc所有参数优先给SystemProperties
                        RoPubArgments.SystemProperties = RoPubArgments.GuiTccInfo.GuiProperties;
                    }
                    GetAllProperties gettcspro = new GetAllProperties(propertylist);
                    RoPubArgments.SystemProperties = gettcspro.BackList;
                    //验证返回值
                    if (RoPubArgments.SystemProperties != null)
                    {
                        argsResult = true;
                    }
                    else
                    {
                        //添加输出
                        if (RoPubArgments.ProTips)
                        {
                            RoOutputToGui roOutputToGui = new RoOutputToGui();
                            //获取当前时间
                            string nowtime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
                            roOutputToGui.OutDetail(nowtime, "方法TestConfigNodes执行失败，拼接全部参数失败，反馈值为NULL");
                        }
                        else
                        {
                            RoPubArgments.RoOutputToConsole.OutputConsole(RoLogStatus.Fatal, "方法TestConfigNodes执行失败，拼接全部参数失败，反馈值为NULL");
                        }

                        RoPubArgments.RoLog.Fatal("方法TestConfigNodes执行失败，拼接全部参数失败，反馈值为NULL");
                        argsResult = false;
                    }
                }
                else
                {
                    //添加输出
                    if (RoPubArgments.ProTips)
                    {
                        RoOutputToGui roOutputToGui = new RoOutputToGui();
                        //获取当前时间
                        string nowtime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
                        roOutputToGui.OutDetail(nowtime, "方法TestConfigNodes执行失败，反序列化获取Properties信息失败，获取值为NULL");
                    }
                    else
                    {
                        RoPubArgments.RoOutputToConsole.OutputConsole(RoLogStatus.Fatal, "方法TestConfigNodes执行失败，反序列化获取Properties信息失败，获取值为NULL");
                    }

                    RoPubArgments.RoLog.Fatal("方法TestConfigNodes执行失败，反序列化获取Properties信息失败，获取值为NULL");
                    argsResult = false;
                }


                //todo (2)开始处理Tci文件，当前tci文件未缓存进入程序，根据tci文件类型进行区分缓存，因为涉及到的泛型和namespace不一样
                //初始化WebTci
                RoPubArgments.UseTciInfo.RoWebTci = new List<RoWeb.ControlUseType>();

                List<ConfigurationFile> configlList = _newSerChildNode.SerConfigurationFileNode(xmlNode.LastChild);
                if (configlList != null)
                {
                    //将所有的Tci文件进行缓存
                    foreach (ConfigurationFile sigconfile in configlList)
                    {
                        //按照Tci的类型进行区分缓存处理，通过泛型回调
                        switch (sigconfile.Type)
                        {
                            case "RoWeb":

                                ExtractTciInfo<RoWeb.ControlUseType> webTciInfo = new ExtractTciInfo<RoWeb.ControlUseType>(sigconfile);
                                RoWeb.ControlUseType back = webTciInfo.BackType;

                                //todo  所有tci新都会被保存在一个全局变量中，只有在脚本开始执行后再开始读取 不在是在执行后再多次读取XML文件
                                RoPubArgments.UseTciInfo.RoWebTci.Add(back);
                                break;
                            case "RoClient": //暂不更新，后期更新
                                break;
                            case "Mobile": //暂不更新
                                break;
                        }
                    }
                    tciResult = true;
                }
                else
                {
                    //添加输出
                    if (RoPubArgments.ProTips)
                    {
                        RoOutputToGui roOutputToGui = new RoOutputToGui();
                        //获取当前时间
                        string nowtime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
                        roOutputToGui.OutDetail(nowtime, "方法TestConfigNodes执行失败，反序列化获取TciImport信息失败，获取值为NULL");
                    }
                    else
                    {
                        RoPubArgments.RoOutputToConsole.OutputConsole(RoLogStatus.Fatal, "方法TestConfigNodes执行失败，反序列化获取TciImport信息失败，获取值为NULL");
                    }

                    RoPubArgments.RoLog.Fatal("方法TestConfigNodes执行失败，反序列化获取TciImport信息失败，获取值为NULL");
                    tciResult = false;
                }

                return argsResult && tciResult;
            }
            catch (Exception e)
            {
                //添加输出
                ExceptionOutPut.SystemExceptionOut("TestConfigNodes", e);
                return false;
            }
        }


        /// <summary>
        /// StartAppNodes节点处理
        /// 处理web浏览器驱动
        /// </summary> 
        /// <param name="xmlNode">StartApp节点</param>
        /// <returns>返回是否正常完成</returns>
        public bool StartAppNodes(XmlNode xmlNode)
        {
            try
            {
                AppInfo appInfo = _newSerChildNode.SerStartApp(xmlNode);
                if (appInfo == null)
                {
                    //添加输出
                    RoPubArgments.RoOutputToConsole.OutputConsole(RoLogStatus.Fatal, "方法StartAppNodes执行失败，反序列化获取StartApp信息失败，获取值为NULL");
                    RoPubArgments.RoLog.Fatal("方法StartAppNodes执行失败，反序列化获取StartApp信息失败，获取值为NULL");
                    return false;
                }
                //将浏览器驱动解压至指定路径
                return UnZipDriver.ExtractZipFileIntoFolder(appInfo);
            }
            catch (Exception e)
            {
                //添加输出
                ExceptionOutPut.SystemExceptionOut("StartAppNodes", e);
                return false;
            }
        }


        /// <summary>
        /// TestsNodes节点处理
        /// 存放测试步骤
        /// </summary>
        /// <param name="xmlNode">Tests节点</param>
        /// <returns>返回是否正常完成</returns>
        public bool TestsNodes(XmlNode xmlNode)

        {
            //Todo 2017-05-04更新
            /*################################################################################################
                 * 现在TestCase不仅是tests的子节点，也是RepeatTest和IterationTest的子节点。因此逻辑执行要重新写下
                 * 当前执行逻辑
                 * （1）TestCase， 正常的执行逻辑，一步步往下执行
                 * （2）RepeatTest，循环测试，包含的TestCase或MacroReference不断循环执行，执行次数由RepeatTest的Counter值控制
                 * （3）IterationTest，迭代测试，包含的TestCase或MacroReference依次进行，其中的某些参数由Lists控制
                 
                 *允许3类逻辑混用，即支持一个steps内包含多个执行逻辑 
            ################################################################################################*/

            try
            {
                //所有的testcase队列，写入队列能保证整个系统中仅存在一个正在执行的testcase ，防止使用循环导致可能的奔溃问题
                Queue<object> allObjTest = new Queue<object>();


                //创建运行结果反馈list
                List<bool> testsBools = new List<bool>();

                //将所有的testcase写入一个队列中，然后在通过循环不断提取进行执行活动
                foreach (XmlNode signode in xmlNode)
                {
                    //普通测试用例
                    if (signode.Name == "tcs:TestCase")
                    {
                        //将单个testcase的步骤写入一个队列中
                        TestcaseInfo sigTestcaseInfo = _newSerChildNode.SerTestcaseInfo(signode);
                        //加入队列
                        allObjTest.Enqueue(sigTestcaseInfo);
                    }
                    //循环测试
                    if (signode.Name == "tcs:RepeatTest")
                    {
                        //将单个testcase的步骤写入一个队列中
                        RepeatInfo repeatInfo = _newSerChildNode.SerRepeatInfo(signode);
                        //加入队列
                        allObjTest.Enqueue(repeatInfo);
                    }
                    //迭代测试
                    if (signode.Name == "tcs:IterationTest")
                    {
                        //将单个testcase的步骤写入一个队列中
                        IterationInfo iterationInfo = _newSerChildNode.SerIterationInfo(signode);
                        //加入队列
                        allObjTest.Enqueue(iterationInfo);
                    }
                }


                //执行逻辑
                while (!allObjTest.IsNullOrEmpty())
                {
                    object sigObj = allObjTest.Dequeue();
                    //通过泛型传入
                    OneTestAction<object> onecase = new OneTestAction<object>(sigObj);
                    bool back = onecase.OneTestResult;
                    testsBools.Add(back);
                }

                //判断整个testcase执行完成后的结果是否包含false结果
                return !testsBools.Contains(false);
            }
            catch (Exception e)
            {
                //添加输出
                ExceptionOutPut.SystemExceptionOut("TestsNodes", e);
                return false;
            }
        }


        /// <summary>
        /// CloseApp节点处理
        /// 处理web浏览器驱动
        /// </summary>
        /// <param name="xmlNode">CloseApp节点</param>
        /// <returns>返回是否正常完成</returns>
        public bool CloseAppNodes(XmlNode xmlNode)
        {
            CloseApp closeApp = _newSerChildNode.SerCloseApp(xmlNode);
            try
            {
                if (closeApp == null)
                {
                    //添加输出
                    if (RoPubArgments.ProTips)
                    {
                        RoOutputToGui roOutputToGui = new RoOutputToGui();
                        //获取当前时间
                        string nowtime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
                        roOutputToGui.OutDetail(nowtime, "方法CloseAppNodes执行失败，反序列化获取CloseApp信息失败，获取值为NULL");
                    }
                    else
                    {
                        RoPubArgments.RoOutputToConsole.OutputConsole(RoLogStatus.Fatal, "方法CloseAppNodes执行失败，反序列化获取CloseApp信息失败，获取值为NULL");
                    }

                    RoPubArgments.RoLog.Fatal("方法CloseAppNodes执行失败，反序列化获取CloseApp信息失败，获取值为NULL");
                    return false;
                }
                //返回操作

                return CloseAppFun.CloseAppFuns(closeApp);
            }
            catch (Exception e)
            {
                //添加输出
                ExceptionOutPut.SystemExceptionOut("CloseAppNodes", e);
                return false;
            }
        }


        /// <summary>
        /// LogFunction节点处理
        /// 打包log到指定路径
        /// </summary>
        /// <param name="xmlNode">LogFunction节点</param>
        /// <returns>返回是否正常完成</returns>
        public bool LogFunctionNodes(XmlNode xmlNode)
        {
            LogFunction logFunction = _newSerChildNode.SerLogFunction(xmlNode);

            try
            {
                if (logFunction == null)
                {
                    //添加输出
                    if (RoPubArgments.ProTips)
                    {
                        RoOutputToGui roOutputToGui = new RoOutputToGui();
                        //获取当前时间
                        string nowtime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
                        roOutputToGui.OutDetail(nowtime, "方法LogFunctionNodes执行失败，反序列化获取LogFunction信息失败，获取值为NULL");
                    }
                    else
                    {
                        RoPubArgments.RoOutputToConsole.OutputConsole(RoLogStatus.Fatal, "方法LogFunctionNodes执行失败，反序列化获取LogFunction信息失败，获取值为NULL");
                    }

                    RoPubArgments.RoLog.Fatal("方法LogFunctionNodes执行失败，反序列化获取LogFunction信息失败，获取值为NULL");
                    return false;
                }
                //返回操作

                return SaveLogIntoFloders.SaveLogIntoFolder(logFunction);
            }
            catch (Exception e)
            {
                //添加输出
                ExceptionOutPut.SystemExceptionOut("LogFunctionNodes", e);
                return false;
            }
        }
    }
}